package com.supor.nfc.lib.utils;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.nfc.tech.Ndef;
import android.nfc.tech.NfcA;
import android.nfc.tech.NfcF;
import android.nfc.tech.NfcV;
import android.os.Build;
import android.os.Parcelable;
import android.provider.Settings;
import android.util.Log;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Locale;

/**
 * ---------------------------------------------------------------- <br>
 * Copyright (C) 2014-2020, by het, Shenzhen, All rights reserved.  <br>
 * ---------------------------------------------------------------- <br>
 * <p>
 * 描述: NfcUtils <br>
 * 作者: lei <br>
 * 日期: 2020/8/5 <br>
 */
public class NfcUtils {
    private static final String TAG = "nfc";
    public static NfcAdapter mNfcAdapter;
    public static IntentFilter[] mIntentFilter = null;
    public static PendingIntent mPendingIntent = null;
    public static String[][] mTechList = null;
    /**
     * NFC i/o操作类
     */
    public static IsoDep isodep = null;
    public static NfcA nfcA = null;
    /**
     * NFC支持状态：0默认支持，1不支持，2未打开
     */
    public static int NFC_STATE = 0;

    public NfcUtils(Activity activity) {
        mNfcAdapter = NfcCheck(activity);
        // NfcInit(activity);
    }

    public static void init(Activity activity) {
        mNfcAdapter = NfcCheck(activity);
        // NfcInit(activity);
    }

    /**
     * 检查NFC是否打开
     */
    public static NfcAdapter NfcCheck(Activity activity) {
        NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(activity.getApplicationContext());
        if (mNfcAdapter == null) {
            NFC_STATE = 1;
            // Toast.makeText(activity, "设备不支持NFC功能!", Toast.LENGTH_SHORT).show();
            return null;
        } else {
            if (!mNfcAdapter.isEnabled()) {
                NFC_STATE = 2;
                // IsToSet(activity);
            } else {
                NFC_STATE = 0;
                // Toast.makeText(activity, "NFC功能已打开!", Toast.LENGTH_SHORT).show();
            }
        }
        return mNfcAdapter;
    }

    public static boolean isSupport(Context context) {
        return (NfcAdapter.getDefaultAdapter(context) != null);
    }

    /**
     * 初始化nfc
     */
    public static void configNfc(Activity activity) {
        Intent intent = new Intent(activity, activity.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        mPendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
        //--------------lei-s------------
        //做一个IntentFilter过滤你想要的action 这里过滤的是ndef
        // IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        //如果你对action的定义有更高的要求，比如data的要求，你可以使用如下的代码来定义intentFilter
        //        IntentFilter filter2 = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        //        try {
        //            filter.addDataType("*/*");
        //        } catch (IntentFilter.MalformedMimeTypeException e) {
        //            e.printStackTrace();
        //        }
        //        mIntentFilter = new IntentFilter[]{filter, filter2};
        //        mTechList = null;
        // try {
        //     filter.addDataType("*/*");
        // } catch (IntentFilter.MalformedMimeTypeException e) {
        //     e.printStackTrace();
        // }
        // mTechList = new String[][]{{MifareClassic.class.getName()},
        //         {NfcA.class.getName()}};
        // //生成intentFilter
        // mIntentFilter = new IntentFilter[]{filter};
        //-----------lei-e----------
        try {

            mTechList = new String[][]{
                    {IsoDep.class.getName()}, {NfcV.class.getName()},
                    {NfcF.class.getName()}, {NfcA.class.getName()}};

            mIntentFilter = new IntentFilter[]{
                    new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED, "*/*")};

        } catch (IntentFilter.MalformedMimeTypeException e) {
            e.printStackTrace();
            Log.e(TAG, "onResume-exception");
        }
    }

    public static boolean isodepConnect(Intent intent) {
        final Parcelable p = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (p == null) {
            Log.e(TAG, "EXTRA_TAG is null, not nfc start ");
            isodep = null;
            return false;
        }
        Tag tag = (Tag) p;
        isodep = IsoDep.get(tag);
        try {
            isodep.connect();
        } catch (Exception e) {
            isodep = null;
            return false;
        }
        return true;
    }

    /**
     * nfcA连接
     *
     * @param intent
     * @return
     */
    public static boolean nfcAConnect(Intent intent) {
        final Parcelable p = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (p == null) {
            Log.e(TAG, "EXTRA_TAG is null, not nfc start ");
            nfcA = null;
            return false;
        }
        if (nfcA != null && nfcA.isConnected()) {
            try {
                nfcA.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        Tag tag = (Tag) p;
        nfcA = NfcA.get(tag);
        try {
            nfcA.connect();
        } catch (Exception e) {
            nfcA = null;
            return false;
        }
        return true;
    }

    /***
     * isoDep类型发送数据
     *
     * @param cmd 发送内容
     * @return 返回数据
     */
    public static byte[] isoTransceive(byte[] cmd) {
        if (null == isodep) {
            Log.e(TAG, "iosdep is null");
            return null;
        }
        byte[] response;
        try {
            response = isodep.transceive(cmd);
            return response;
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "无响应,请检查卡片位置是否放置正确");
            return null;
        }
    }

    /***
     * nfcA类型发送数据
     *
     * @param cmd 发送内容
     * @return 返回数据
     */
    public static byte[] nfcATransceive(byte[] cmd) {
        if (null == nfcA) {
            Log.e(TAG, "nfcA is null");
            return null;
        }
        byte[] response;
        try {
            response = nfcA.transceive(cmd);
            return response;
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "无响应,请检查卡片位置是否放置正确");
            return null;
        }
    }

    /**
     * 读取NFC的NDEF数据
     *
     * @param intent intent
     * @param number 自定义进制返回，16表示返回16进制字符串
     */
    public static String readNFCFromNdef(Intent intent, int number) {
        Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawArray != null) {
            NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
            NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
            if (mNdefRecord != null) {
                // Logc.e("ndef.getType: " + new String(mNdefRecord.getType(), StandardCharsets
                // .UTF_8));
                if (number == 16) {
                    return HexUtil.encodeHexStr(mNdefRecord.getPayload(), false);
                } else {
                    return new String(mNdefRecord.getPayload(), StandardCharsets.UTF_8);
                }
            }
        }
        return "";
    }

    /**
     * 读取NFC的NDEF tag数据
     *
     * @param intent intent
     * @param number 自定义进制返回，16表示返回16进制字符串
     */
    public static String readNFCFromTag(Intent intent, int number) {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (tag == null) {
            return "";
        }
        Ndef ndef = null;
        try {
            ndef = Ndef.get(tag);
            ndef.connect();
            NdefMessage ndefMessage = ndef.getNdefMessage();
            if (ndefMessage == null) {
                ndef.close();
                Log.e(TAG, "ndefMessage is null");
                return "";
            }
            NdefRecord mNdefRecord = ndefMessage.getRecords()[0];
            if (mNdefRecord != null) {
                // Logc.e("ndef.getType: " + new String(mNdefRecord.getType(), StandardCharsets
                // .UTF_8));
                if (number == 16) {
                    return HexUtil.encodeHexStr(mNdefRecord.getPayload(), false);
                } else {
                    return new String(mNdefRecord.getPayload(), StandardCharsets.UTF_8);
                }
            }
            // ndef.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ndef != null) {
                try {
                    ndef.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return "";
    }

    /**
     * 读取NFC的NdefRecord
     *
     * @param intent intent
     */
    public static NdefRecord readNdefRecordFromTag(Intent intent) {
        Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawArray != null) {
            NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
            return mNdefMsg.getRecords()[0];
        }
        return null;
    }

    /**
     * 读取NFC的NdefRecord
     *
     * @param intent intent
     */
    public static NdefRecord[] readNdefRecordsFromTag(Intent intent) {
        Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawArray != null) {
            NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
            return mNdefMsg.getRecords();
        }
        return null;
    }

    /**
     * 往nfc写入数据
     */
    public static boolean writeNFCToTag(String data, Intent intent) {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (tag == null) {
            return false;
        }
        try {
            Ndef ndef = Ndef.get(tag);
            ndef.connect();
            NdefRecord ndefRecord = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ndefRecord = NdefRecord.createTextRecord(null, data);
            }
            NdefRecord[] records = {ndefRecord};
            NdefMessage ndefMessage = new NdefMessage(records);

            ndef.writeNdefMessage(ndefMessage);
            ndef.close();
            return true;
        } catch (IOException | FormatException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 往nfc写入数据，用media type写启动方式
     *
     * @param data   写入NFC的数据
     * @param intent intent
     */
    public static boolean writeNFCMediaToTag(byte[] data, Intent intent) {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (tag == null) {
            return false;
        }
        Ndef ndef = null;
        try {
            ndef = Ndef.get(tag);
            ndef.connect();
            // Logc.e("ndef.getMaxSize: " + ndef.getMaxSize());
            NdefRecord ndefRecord = null;
            // ndefRecord = NdefRecord.createUri("https://www.baidu.com?id=10&p=Android");
            // ndefRecord = NdefRecord.createUri("https://www.baidu.com?id=10&p=Android");
            ndefRecord = createMedia("iot", "supor.app", data);
            NdefRecord[] records = {ndefRecord};
            NdefMessage ndefMessage = new NdefMessage(records);
            ndef.writeNdefMessage(ndefMessage);
            // ndef.close();
            return true;
        } catch (IOException | FormatException e) {
            e.printStackTrace();
        } finally {
            if (ndef != null) {
                try {
                    ndef.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    public static NdefRecord createExternal(String domain, String type, byte[] data) {
        if (domain == null)
            throw new NullPointerException("domain is null");
        if (type == null)
            throw new NullPointerException("type is null");

        domain = domain.trim().toLowerCase(Locale.ROOT);
        type = type.trim().toLowerCase(Locale.ROOT);

        if (domain.length() == 0)
            throw new IllegalArgumentException("domain is empty");
        if (type.length() == 0)
            throw new IllegalArgumentException("type is empty");

        byte[] byteDomain = domain.getBytes(StandardCharsets.UTF_8);
        byte[] byteType = type.getBytes(StandardCharsets.UTF_8);
        byte[] b = new byte[byteDomain.length + 1 + byteType.length];
        System.arraycopy(byteDomain, 0, b, 0, byteDomain.length);
        b[byteDomain.length] = '/';
        System.arraycopy(byteType, 0, b, byteDomain.length + 1, byteType.length);

        return new NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE, b, null, data);
    }

    public static NdefRecord createMedia(String domain, String type, byte[] data) {
        if (domain == null) throw new NullPointerException("domain is null");
        if (type == null) throw new NullPointerException("type is null");

        domain = domain.trim().toLowerCase(Locale.ROOT);
        type = type.trim().toLowerCase(Locale.ROOT);

        if (domain.length() == 0) throw new IllegalArgumentException("domain is empty");
        if (type.length() == 0) throw new IllegalArgumentException("type is empty");

        byte[] byteDomain = domain.getBytes(StandardCharsets.UTF_8);
        byte[] byteType = type.getBytes(StandardCharsets.UTF_8);
        byte[] b = new byte[byteDomain.length + 1 + byteType.length];
        System.arraycopy(byteDomain, 0, b, 0, byteDomain.length);
        b[byteDomain.length] = '/';
        System.arraycopy(byteType, 0, b, byteDomain.length + 1, byteType.length);

        return new NdefRecord(NdefRecord.TNF_MIME_MEDIA, b, null, data);
    }

    /**
     * 读取nfcID
     */
    public static String readNFCId(Intent intent) throws UnsupportedEncodingException {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        String id = ByteArrayToHexString(tag.getId());
        return id;
    }

    /**
     * 将字节数组转换为字符串
     */
    private static String ByteArrayToHexString(byte[] inarray) {
        int i, j, in;
        String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E"
                , "F"};
        String out = "";

        for (j = 0; j < inarray.length; ++j) {
            in = (int) inarray[j] & 0xff;
            i = (in >> 4) & 0x0f;
            out += hex[i];
            i = in & 0x0f;
            out += hex[i];
        }
        return out;
    }

    private static void IsToSet(final Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("是否跳转到设置页面打开NFC功能");
        //        builder.setTitle("提示");
        builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                goToSet(activity);
                dialog.dismiss();
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.create().show();
    }

    private static void goToSet(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE) {
            // 进入设置系统应用权限界面
            Intent intent = new Intent(Settings.ACTION_SETTINGS);
            activity.startActivity(intent);
            return;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {// 运行系统在5.x环境使用
            // 进入设置系统应用权限界面
            Intent intent = new Intent(Settings.ACTION_SETTINGS);
            activity.startActivity(intent);
            return;
        }
    }

    /**
     * 检查NFC权限是否打开，针对小米手机
     *      op=10016 对应 NFC
     *      op=10021 对应 后台弹出界面
     *
     * @param context
     * @param op
     * @return
     */
    private boolean checkOpPermission(Context context, int op) {
        try {
            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            Method method = manager.getClass().getMethod("checkOpNoThrow", int.class, int.class,
                    String.class);
            int result = (int) method.invoke(manager, op, android.os.Process.myUid(), context.getPackageName());
            return AppOpsManager.MODE_ALLOWED == result;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static boolean hasBackgroundStartPermissionInMIUI(Context context) {
        AppOpsManager ops = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        try {
            // ops.checkOpNoThrow(op, uid, packageName)
            Field field = AppOpsManager.class.getField("OP_BACKGROUND_START_ACTIVITY");
            field.setAccessible(true);
            int opValue = (int) field.get(ops);
            Method method = ops.getClass().getMethod("checkOpNoThrow", int.class, int.class, String.class);
            Integer result = (Integer) method.invoke(ops, opValue, android.os.Process.myUid(), context.getPackageName());
            return result == AppOpsManager.MODE_ALLOWED;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
